
package net.lab0.fractal.gui;


import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.File;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import net.lab0.fractal.abstracts.AbstractManageableUI2DFractal;
import net.lab0.fractal.abstracts.FractalState;
import net.lab0.fractal.classes.RenderingCoordinates;
import net.lab0.fractal.event.FractalComponentMouseCoordinates;
import net.lab0.fractal.event.FractalComponentMouseCoordinatesListener;
import net.lab0.fractal.event.FractalStateEvent;
import net.lab0.fractal.event.FractalStateListener;
import net.lab0.fractal.event.ProgressEvent;
import net.lab0.fractal.event.ProgressListener;
import net.lab0.fractal.fractals.mandelbrot.BasicMandelbrotFractal;
import net.lab0.fractal.fractals.mandelbrot.MultithreadedMandelbrotFractal;
import nu.xom.ParsingException;
import nu.xom.ValidityException;

import org.apache.log4j.Logger;
import org.jdesktop.beansbinding.AutoBinding;
import org.jdesktop.beansbinding.AutoBinding.UpdateStrategy;
import org.jdesktop.beansbinding.BeanProperty;
import org.jdesktop.beansbinding.Bindings;


@SuppressWarnings("serial")
public class FractalPanel
extends JPanel
implements ProgressListener, FractalStateListener
{
    private static Logger                 logger = Logger.getLogger(FractalPanel.class);
    
    private AbstractManageableUI2DFractal fractal;
    private MandelbrotComponent           mandelbrotComponent;
    private JPanel                        panel;
    private JLabel                        lblNewLabel;
    private JPanel                        panel_1;
    private JLabel                        lblIterations;
    private JLabel                        lblNewLabel_1;
    private JLabel                        lblResolution;
    private JLabel                        lblIterationCount;
    private JLabel                        lblProgress;
    private JProgressBar                  progressBar;
    private JCheckBox                     chckbxPause;
    private JButton                       btnNewButton;
    private JLabel                        lblsdfggg;
    private JLabel                        lblState;
    private JPanel                        panel_2;
    private JLabel                        lblNewLabel_3;
    private JLabel                        lblNewLabel_4;
    private JSlider                       slider;
    private StatusPanel                   statusPanel;
    private JCheckBox                     chckbxMandelbrotQuadTree;
    private JSpinner                      spinner;
    private JLabel                        lblNewLabel_5;
    private JPanel                        panel_3;
    private JLabel                        lblMaxIterations;
    private JSpinner                      spinner_1;
    private JComboBox                     comboBox;
    private JButton                       btnSave;
    private JProgressBar                  progressBarQuadTree;
    private JProgressBar                  progressBarSteps;
    private JPanel panel_4;
    private JButton btnLoad;
    
    public FractalPanel(AbstractManageableUI2DFractal fractal)
    {
        if (fractal == null)
        {
            throw new NullPointerException("AbstractUI2DFractalInterface can't be null in " + getClass().getSimpleName());
        }
        mandelbrotComponent = new MandelbrotComponent(fractal);
        changeFractal(fractal);
        initComponents();
        mandelbrotComponent.getMandelbrotQuadTree().addEventListener(new MandelbrotQuadTreeListener()
        {
            @Override
            public void updateProgress(final int percentage)
            {
                SwingUtilities.invokeLater(new Runnable()
                {
                    
                    @Override
                    public void run()
                    {
                        progressBarQuadTree.setValue(percentage);
                    }
                });
            }
            
            @Override
            public void updateEdgeComputationFinished(MandelbrotZoneEdgeTest mandelbrotZoneEdgeTest)
            {
                // TODO Auto-generated method stub
                
            }
            
            @Override
            public void updateComputingPass(final int level, final int maxLevel)
            {
                SwingUtilities.invokeLater(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        progressBarSteps.setValue(level * 100 / maxLevel);
                    }
                });
            }

			@Override
			public void updateZoneComputationFinished(MandelbrotZoneTestInterface mandelbrotZoneTest)
			{
				// TODO Auto-generated method stub
				
			}
        });
    }
    
    private void initComponents()
    {
        addComponentListener(new ComponentAdapter()
        {
            @Override
            public void componentResized(ComponentEvent e)
            {
                fractal.restartComputation();
            }
        });
        setLayout(new BorderLayout(0, 0));
        
        add(mandelbrotComponent, BorderLayout.CENTER);
        
        panel = new JPanel();
        add(panel, BorderLayout.WEST);
        GridBagLayout gbl_panel = new GridBagLayout();
        gbl_panel.columnWidths = new int[] { 150, 0 };
        gbl_panel.rowHeights = new int[] { 0, 0, 0, 0 };
        gbl_panel.columnWeights = new double[] { 1.0, Double.MIN_VALUE };
        gbl_panel.rowWeights = new double[] { 1.0, 0.0, 1.0, Double.MIN_VALUE };
        panel.setLayout(gbl_panel);
        
        panel_1 = new JPanel();
        panel_1.setBorder(new TitledBorder(null, "Fractal", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        GridBagConstraints gbc_panel_1 = new GridBagConstraints();
        gbc_panel_1.insets = new Insets(0, 0, 5, 0);
        gbc_panel_1.fill = GridBagConstraints.BOTH;
        gbc_panel_1.gridx = 0;
        gbc_panel_1.gridy = 0;
        panel.add(panel_1, gbc_panel_1);
        GridBagLayout gbl_panel_1 = new GridBagLayout();
        gbl_panel_1.columnWidths = new int[] { 46, 0, 0 };
        gbl_panel_1.rowHeights = new int[] { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        gbl_panel_1.columnWeights = new double[] { 1.0, 1.0, Double.MIN_VALUE };
        gbl_panel_1.rowWeights = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE };
        panel_1.setLayout(gbl_panel_1);
        
        lblNewLabel = new JLabel("Resolution");
        GridBagConstraints gbc_lblNewLabel = new GridBagConstraints();
        gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5);
        gbc_lblNewLabel.anchor = GridBagConstraints.NORTHWEST;
        gbc_lblNewLabel.gridx = 0;
        gbc_lblNewLabel.gridy = 0;
        panel_1.add(lblNewLabel, gbc_lblNewLabel);
        
        lblResolution = new JLabel("x");
        GridBagConstraints gbc_lblResolution = new GridBagConstraints();
        gbc_lblResolution.insets = new Insets(0, 0, 5, 0);
        gbc_lblResolution.gridx = 1;
        gbc_lblResolution.gridy = 0;
        panel_1.add(lblResolution, gbc_lblResolution);
        
        lblIterations = new JLabel("Iterations");
        GridBagConstraints gbc_lblIterations = new GridBagConstraints();
        gbc_lblIterations.anchor = GridBagConstraints.WEST;
        gbc_lblIterations.insets = new Insets(0, 0, 5, 5);
        gbc_lblIterations.gridx = 0;
        gbc_lblIterations.gridy = 1;
        panel_1.add(lblIterations, gbc_lblIterations);
        
        lblIterationCount = new JLabel("" + fractal.getMaxIteration());
        GridBagConstraints gbc_lblIterationCount = new GridBagConstraints();
        gbc_lblIterationCount.insets = new Insets(0, 0, 5, 0);
        gbc_lblIterationCount.gridx = 1;
        gbc_lblIterationCount.gridy = 1;
        panel_1.add(lblIterationCount, gbc_lblIterationCount);
        
        lblNewLabel_1 = new JLabel("Class");
        GridBagConstraints gbc_lblNewLabel_1 = new GridBagConstraints();
        gbc_lblNewLabel_1.anchor = GridBagConstraints.WEST;
        gbc_lblNewLabel_1.insets = new Insets(0, 0, 5, 5);
        gbc_lblNewLabel_1.gridx = 0;
        gbc_lblNewLabel_1.gridy = 2;
        panel_1.add(lblNewLabel_1, gbc_lblNewLabel_1);
        
        btnNewButton = new JButton("Start computation");
        btnNewButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                fractal.startComputation();
            }
        });
        
        comboBox = new JComboBox();
        comboBox.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                if (comboBox.getSelectedItem().equals(MultithreadedMandelbrotFractal.class))
                {
                    changeFractal(new MultithreadedMandelbrotFractal(fractal.getRenderingCoordinates(), fractal.getMaxIteration(), 0.1f, 1000, Runtime.getRuntime()
                    .availableProcessors()));
                }
                else if (comboBox.getSelectedItem().equals(BasicMandelbrotFractal.class))
                {
                    changeFractal(new BasicMandelbrotFractal(fractal.getRenderingCoordinates(), fractal.getMaxIteration(), 0.1f, 1000));
                }
            }
        });
        GridBagConstraints gbc_comboBox = new GridBagConstraints();
        gbc_comboBox.insets = new Insets(0, 0, 5, 0);
        gbc_comboBox.fill = GridBagConstraints.HORIZONTAL;
        gbc_comboBox.gridx = 1;
        gbc_comboBox.gridy = 2;
        panel_1.add(comboBox, gbc_comboBox);
        comboBox.addItem(BasicMandelbrotFractal.class);
        comboBox.addItem(MultithreadedMandelbrotFractal.class);
        comboBox.setRenderer(new FractalComboboxListRenderer());
        
        lblsdfggg = new JLabel("State");
        GridBagConstraints gbc_lblsdfggg = new GridBagConstraints();
        gbc_lblsdfggg.anchor = GridBagConstraints.WEST;
        gbc_lblsdfggg.insets = new Insets(0, 0, 5, 5);
        gbc_lblsdfggg.gridx = 0;
        gbc_lblsdfggg.gridy = 3;
        panel_1.add(lblsdfggg, gbc_lblsdfggg);
        
        lblState = new JLabel(fractal.getState().getText());
        GridBagConstraints gbc_lblState = new GridBagConstraints();
        gbc_lblState.insets = new Insets(0, 0, 5, 0);
        gbc_lblState.gridx = 1;
        gbc_lblState.gridy = 3;
        panel_1.add(lblState, gbc_lblState);
        GridBagConstraints gbc_btnNewButton = new GridBagConstraints();
        gbc_btnNewButton.fill = GridBagConstraints.HORIZONTAL;
        gbc_btnNewButton.gridwidth = 2;
        gbc_btnNewButton.insets = new Insets(0, 0, 5, 0);
        gbc_btnNewButton.gridx = 0;
        gbc_btnNewButton.gridy = 4;
        panel_1.add(btnNewButton, gbc_btnNewButton);
        
        lblProgress = new JLabel("Progress");
        GridBagConstraints gbc_lblProgress = new GridBagConstraints();
        gbc_lblProgress.insets = new Insets(0, 0, 5, 5);
        gbc_lblProgress.gridx = 0;
        gbc_lblProgress.gridy = 5;
        panel_1.add(lblProgress, gbc_lblProgress);
        
        progressBar = new JProgressBar();
        progressBar.setStringPainted(true);
        GridBagConstraints gbc_progressBar = new GridBagConstraints();
        gbc_progressBar.insets = new Insets(0, 0, 5, 0);
        gbc_progressBar.gridwidth = 2;
        gbc_progressBar.gridx = 0;
        gbc_progressBar.gridy = 6;
        panel_1.add(progressBar, gbc_progressBar);
        
        chckbxPause = new JCheckBox("Pause");
        chckbxPause.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                if (!fractal.getState().equals(FractalState.PAUSED))
                {
                    if (chckbxPause.isSelected())
                    {
                        fractal.pauseComputation();
                    }
                    else
                    {
                        // should not happen
                    }
                }
                else
                {
                    if (chckbxPause.isSelected())
                    {
                        // no nothing
                    }
                    else
                    {
                        fractal.unpauseComputation();
                    }
                }
            }
        });
        
        GridBagConstraints gbc_chckbxPause = new GridBagConstraints();
        gbc_chckbxPause.insets = new Insets(0, 0, 5, 0);
        gbc_chckbxPause.anchor = GridBagConstraints.WEST;
        gbc_chckbxPause.gridwidth = 2;
        gbc_chckbxPause.gridx = 0;
        gbc_chckbxPause.gridy = 7;
        panel_1.add(chckbxPause, gbc_chckbxPause);
        
        panel_3 = new JPanel();
        GridBagConstraints gbc_panel_3 = new GridBagConstraints();
        gbc_panel_3.fill = GridBagConstraints.HORIZONTAL;
        gbc_panel_3.insets = new Insets(0, 0, 5, 0);
        gbc_panel_3.gridx = 0;
        gbc_panel_3.gridy = 1;
        panel.add(panel_3, gbc_panel_3);
        panel_3.setBorder(new TitledBorder(null, "Quad Trees", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        GridBagLayout gbl_panel_3 = new GridBagLayout();
        gbl_panel_3.columnWidths = new int[] { 0, 0, 0 };
        gbl_panel_3.rowHeights = new int[] { 0, 0, 0, 0, 0, 0, 0 };
        gbl_panel_3.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
        gbl_panel_3.rowWeights = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE };
        panel_3.setLayout(gbl_panel_3);
        
        chckbxMandelbrotQuadTree = new JCheckBox("Mandelbrot QuadTree");
        GridBagConstraints gbc_chckbxMandelbrotQuadTree = new GridBagConstraints();
        gbc_chckbxMandelbrotQuadTree.anchor = GridBagConstraints.WEST;
        gbc_chckbxMandelbrotQuadTree.insets = new Insets(0, 0, 5, 5);
        gbc_chckbxMandelbrotQuadTree.gridx = 0;
        gbc_chckbxMandelbrotQuadTree.gridy = 0;
        panel_3.add(chckbxMandelbrotQuadTree, gbc_chckbxMandelbrotQuadTree);
        
        lblNewLabel_5 = new JLabel("Depth");
        GridBagConstraints gbc_lblNewLabel_5 = new GridBagConstraints();
        gbc_lblNewLabel_5.anchor = GridBagConstraints.WEST;
        gbc_lblNewLabel_5.insets = new Insets(0, 0, 5, 5);
        gbc_lblNewLabel_5.gridx = 0;
        gbc_lblNewLabel_5.gridy = 1;
        panel_3.add(lblNewLabel_5, gbc_lblNewLabel_5);
        
        spinner = new JSpinner();
        GridBagConstraints gbc_spinner = new GridBagConstraints();
        gbc_spinner.insets = new Insets(0, 0, 5, 0);
        gbc_spinner.fill = GridBagConstraints.HORIZONTAL;
        gbc_spinner.gridx = 1;
        gbc_spinner.gridy = 1;
        panel_3.add(spinner, gbc_spinner);
        spinner.addChangeListener(new ChangeListener()
        {
            public void stateChanged(ChangeEvent e)
            {
                new Thread()
                {
                    @Override
                    public void run()
                    {
                        mandelbrotComponent.setMandelbrotQuadTreeDepth((Integer) spinner.getValue());
                        SwingUtilities.invokeLater(new Runnable()
                        {
                            @Override
                            public void run()
                            {
                                mandelbrotComponent.repaint();
                            }
                        });
                    }
                }.start();
                
            }
        });
        spinner.setValue(4);
        
        lblMaxIterations = new JLabel("Max Iterations");
        GridBagConstraints gbc_lblMaxIterations = new GridBagConstraints();
        gbc_lblMaxIterations.anchor = GridBagConstraints.WEST;
        gbc_lblMaxIterations.insets = new Insets(0, 0, 5, 5);
        gbc_lblMaxIterations.gridx = 0;
        gbc_lblMaxIterations.gridy = 2;
        panel_3.add(lblMaxIterations, gbc_lblMaxIterations);
        
        spinner_1 = new JSpinner();
        spinner_1.setValue(4096);
        GridBagConstraints gbc_spinner_1 = new GridBagConstraints();
        gbc_spinner_1.fill = GridBagConstraints.HORIZONTAL;
        gbc_spinner_1.insets = new Insets(0, 0, 5, 0);
        gbc_spinner_1.gridx = 1;
        gbc_spinner_1.gridy = 2;
        panel_3.add(spinner_1, gbc_spinner_1);
        
        progressBarSteps = new JProgressBar();
        GridBagConstraints gbc_progressBarSteps = new GridBagConstraints();
        gbc_progressBarSteps.fill = GridBagConstraints.HORIZONTAL;
        gbc_progressBarSteps.gridwidth = 2;
        gbc_progressBarSteps.insets = new Insets(0, 0, 5, 0);
        gbc_progressBarSteps.gridx = 0;
        gbc_progressBarSteps.gridy = 3;
        panel_3.add(progressBarSteps, gbc_progressBarSteps);
        
        progressBarQuadTree = new JProgressBar();
        progressBarQuadTree.setStringPainted(true);
        GridBagConstraints gbc_progressBarQuadTree = new GridBagConstraints();
        gbc_progressBarQuadTree.fill = GridBagConstraints.HORIZONTAL;
        gbc_progressBarQuadTree.gridwidth = 2;
        gbc_progressBarQuadTree.insets = new Insets(0, 0, 5, 0);
        gbc_progressBarQuadTree.gridx = 0;
        gbc_progressBarQuadTree.gridy = 4;
        panel_3.add(progressBarQuadTree, gbc_progressBarQuadTree);
        
        panel_4 = new JPanel();
        GridBagConstraints gbc_panel_4 = new GridBagConstraints();
        gbc_panel_4.fill = GridBagConstraints.BOTH;
        gbc_panel_4.gridwidth = 2;
        gbc_panel_4.gridx = 0;
        gbc_panel_4.gridy = 5;
        panel_3.add(panel_4, gbc_panel_4);
        GridBagLayout gbl_panel_4 = new GridBagLayout();
        gbl_panel_4.columnWidths = new int[]{0, 0, 0};
        gbl_panel_4.rowHeights = new int[]{0, 0};
        gbl_panel_4.columnWeights = new double[]{1.0, 1.0, Double.MIN_VALUE};
        gbl_panel_4.rowWeights = new double[]{0.0, Double.MIN_VALUE};
        panel_4.setLayout(gbl_panel_4);
        
        btnSave = new JButton("Save");
        GridBagConstraints gbc_btnSave = new GridBagConstraints();
        gbc_btnSave.fill = GridBagConstraints.HORIZONTAL;
        gbc_btnSave.insets = new Insets(0, 0, 0, 5);
        gbc_btnSave.gridx = 0;
        gbc_btnSave.gridy = 0;
        panel_4.add(btnSave, gbc_btnSave);
        
        btnLoad = new JButton("Load");
        btnLoad.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                loadQuadTree();
            }
        });
        GridBagConstraints gbc_btnLoad = new GridBagConstraints();
        gbc_btnLoad.fill = GridBagConstraints.HORIZONTAL;
        gbc_btnLoad.gridx = 1;
        gbc_btnLoad.gridy = 0;
        panel_4.add(btnLoad, gbc_btnLoad);
        btnSave.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                saveQuadTree();
            }
        });
        chckbxMandelbrotQuadTree.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                mandelbrotComponent.setMandelbrotQuadTreeDisplayed(chckbxMandelbrotQuadTree.isSelected());
                mandelbrotComponent.repaint();
            }
        });
        
        panel_2 = new JPanel();
        panel_2.setBorder(new TitledBorder(null, "Parameters", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        GridBagConstraints gbc_panel_2 = new GridBagConstraints();
        gbc_panel_2.fill = GridBagConstraints.BOTH;
        gbc_panel_2.gridx = 0;
        gbc_panel_2.gridy = 2;
        panel.add(panel_2, gbc_panel_2);
        GridBagLayout gbl_panel_2 = new GridBagLayout();
        gbl_panel_2.columnWidths = new int[] { 0, 0, 0 };
        gbl_panel_2.rowHeights = new int[] { 0, 0, 0 };
        gbl_panel_2.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
        gbl_panel_2.rowWeights = new double[] { 0.0, 0.0, Double.MIN_VALUE };
        panel_2.setLayout(gbl_panel_2);
        
        lblNewLabel_3 = new JLabel("Iterations");
        GridBagConstraints gbc_lblNewLabel_3 = new GridBagConstraints();
        gbc_lblNewLabel_3.insets = new Insets(0, 0, 5, 5);
        gbc_lblNewLabel_3.anchor = GridBagConstraints.EAST;
        gbc_lblNewLabel_3.gridx = 0;
        gbc_lblNewLabel_3.gridy = 0;
        panel_2.add(lblNewLabel_3, gbc_lblNewLabel_3);
        
        lblNewLabel_4 = new JLabel("New label");
        GridBagConstraints gbc_lblNewLabel_4 = new GridBagConstraints();
        gbc_lblNewLabel_4.anchor = GridBagConstraints.WEST;
        gbc_lblNewLabel_4.insets = new Insets(0, 0, 5, 0);
        gbc_lblNewLabel_4.gridx = 1;
        gbc_lblNewLabel_4.gridy = 0;
        panel_2.add(lblNewLabel_4, gbc_lblNewLabel_4);
        
        slider = new JSlider();
        slider.setPaintLabels(true);
        slider.setMinimum(1);
        slider.setPaintTicks(true);
        slider.setMajorTickSpacing(1024);
        slider.setMaximum(4097);
        slider.setValue(256);
        GridBagConstraints gbc_slider = new GridBagConstraints();
        gbc_slider.gridwidth = 2;
        gbc_slider.insets = new Insets(0, 0, 0, 5);
        gbc_slider.gridx = 0;
        gbc_slider.gridy = 1;
        panel_2.add(slider, gbc_slider);
        initDataBindings();
        
        statusPanel = new StatusPanel();
        add(statusPanel, BorderLayout.SOUTH);
    }

    private void loadQuadTree()
    {
        try
        {
            JFileChooser fc = new JFileChooser();
            fc.setMultiSelectionEnabled(false);
            fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
            int ret = fc.showSaveDialog(this);
            switch (ret)
            {
                case JFileChooser.APPROVE_OPTION:
                    File f = fc.getSelectedFile();
                    mandelbrotComponent.loadTreeFrom(f);
                    break;
                
                default:
                    break;
            }
        }
        catch (IOException e)
        {
            logger.error("IO Exception", e);
            JOptionPane.showMessageDialog(this, e.getMessage(), "IO Exception", JOptionPane.ERROR_MESSAGE);
        }
        catch (ValidityException e)
        {
            logger.error("IO Exception", e);
            JOptionPane.showMessageDialog(this, e.getMessage(), "IO Exception", JOptionPane.ERROR_MESSAGE);
        }
        catch (ParsingException e)
        {
            logger.error("IO Exception", e);
            JOptionPane.showMessageDialog(this, e.getMessage(), "IO Exception", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    private void saveQuadTree()
    {
        try
        {
            JFileChooser fc = new JFileChooser();
            fc.setMultiSelectionEnabled(false);
            fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
            int ret = fc.showSaveDialog(this);
            switch (ret)
            {
                case JFileChooser.APPROVE_OPTION:
                    File f = fc.getSelectedFile();
                    mandelbrotComponent.saveTreeTo(f);
                    break;
                
                default:
                    break;
            }
        }
        catch (IOException e)
        {
            logger.error("IO Exception", e);
            JOptionPane.showMessageDialog(this, e.getMessage(), "IO Exception", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    private void changeFractal(AbstractManageableUI2DFractal newFractal)
    {
        if (this.fractal != null)
        {
            this.fractal.stopComputation();
        }
        if (newFractal != null)
        {
            this.fractal = newFractal;
            mandelbrotComponent.setFractal(newFractal);
            mandelbrotComponent.addFractalComponentMouseCoordinatesListener(new FractalComponentMouseCoordinatesListener()
            {
                public void mouseCoordinatesupdated(FractalComponentMouseCoordinates event)
                {
                    statusPanel.setCoordinates(event.getPoint());
                }
            });
            mandelbrotComponent.addComponentListener(new ComponentAdapter()
            {
                @Override
                public void componentResized(ComponentEvent e)
                {
                    lblResolution.setText(fractal.getRenderingCoordinates().getxResolution() + " X " + fractal.getRenderingCoordinates().getyResolution());
                }
            });
            newFractal.addProgressListener(this);
            newFractal.addFractalStateListener(this);
        }
    }
    
    public static void main(String[] args)
    {
        BasicMandelbrotFractal fractal = new MultithreadedMandelbrotFractal(new RenderingCoordinates(0.0, 0.0, 4.0, 4.0, 512, 512), 1 << 10, 0.01f, 250, Runtime.getRuntime()
        .availableProcessors());
        JFrame f = new JFrame();
        f.setSize(800, 600);
        f.getContentPane().add(new FractalPanel(fractal));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        f.setVisible(true);
    }
    
    @Override
    public void progression(ProgressEvent event)
    {
        if (event.isFinished())
        {
            progressBar.setIndeterminate(true);
            progressBar.setValue(100);
        }
        else
        {
            progressBar.setIndeterminate(false);
            progressBar.setValue((int) (event.getProgression() * 100));
        }
    }
    
    @Override
    public void fractalStateChanged(FractalStateEvent event)
    {
        if (event.getSource().equals(fractal))
        {
            lblState.setText(event.getState().getText());
            
            if (event.getState().equals(FractalState.PAUSED))
            {
                if (!chckbxPause.isSelected())
                {
                    chckbxPause.setEnabled(false);
                }
            }
            else
            {
                chckbxPause.setSelected(false);
                chckbxPause.setEnabled(true);
            }
        }
    }
    
    protected void initDataBindings()
    {
        BeanProperty<AbstractManageableUI2DFractal, Long> abstractManageableUI2DFractalBeanProperty = BeanProperty.create("maxIteration");
        BeanProperty<JLabel, String> jLabelBeanProperty = BeanProperty.create("text");
        AutoBinding<AbstractManageableUI2DFractal, Long, JLabel, String> autoBinding = Bindings.createAutoBinding(UpdateStrategy.READ_WRITE, fractal,
        abstractManageableUI2DFractalBeanProperty, lblNewLabel_4, jLabelBeanProperty);
        autoBinding.bind();
        //
        BeanProperty<JSlider, Integer> jSliderBeanProperty = BeanProperty.create("value_IGNORE_ADJUSTING");
        AutoBinding<JLabel, String, JSlider, Integer> autoBinding_1 = Bindings.createAutoBinding(UpdateStrategy.READ_WRITE, lblNewLabel_4, jLabelBeanProperty, slider,
        jSliderBeanProperty);
        autoBinding_1.bind();
    }
}
